/*
 * Created by: Mark Lavrynenko
 * Email:	MarkLavrinenko@gmail.com
 * Project:	  Huffman
*/

#include "HTree.h"
#include "FrequencyTable.h"
#include "CodingTable.h"
#include "HuffmanTreeNode.h"
#include "IHTreeCallBack.h"
#ifdef _DEBUG
#include <iostream>
#endif

// why i should white next line???/
vector<char> HTree::path;
CodingTable* HTree::codingTable;

HTree::HTree(HuffmanTreeNode* node) : myDelegate(nullptr), root(node), state(node)
{
}

HTree::~HTree(void)
{
	if (root)
		delete root;
}


void  HTree::archiveByte(uint8_t byte)
{
	
}

void HTree::unArchivebyte(uint8_t byte)
{
	assert(nullptr != myDelegate);
	size_t i = 8;
	do
	{	
		assert(nullptr != state);
		--i;
		bool left = ( 0 != (byte & (1 << i)) );
		if (!left && nullptr != state->left)
		{
			state = state->left;
		}
		else if (left && nullptr != state->right)
		{
			state = state->right;
		}
		// we in leaf
		if (nullptr == state->left && nullptr == state->right)
		{	
			myDelegate->acceptFinishedByte(state->letter);
			state = root;
		}
	}
	while (i>0);
}

CodingTable* HTree::createTable()
{
	codingTable = new CodingTable();
	dfs(root, codingTableBuilder);
	return codingTable;
}

void HTree::dfs(HuffmanTreeNode* ver, CallBack helper, DFSDirection dir)
{
	assert(nullptr != helper);
	// perform callback	

	helper(ver, dir);
	// go deeper
	if (ver->left)
	{
		dfs(ver->left, helper, DFSDirection::TurnLeft);
	}

	if (ver->right)
	{
		dfs(ver->right, helper, DFSDirection::TurnRight);
	}
	// perform another callback
	helper(ver, DFSDirection::Rise);
}

void HTree::codingTableBuilder(HuffmanTreeNode* node, DFSDirection dir)
{
	switch (dir)
	{
	case TurnLeft:
		path.push_back('0');
		break;
	case TurnRight:
		path.push_back('1');
		break;
	case Rise:
		if (!path.empty())
			path.erase(--path.end());
		return;
	case None:
		break;
	default:
		assert(0);
	}
	bool isLeaf = (nullptr == node->left && nullptr == node->right);
	if (isLeaf)
	{
#ifdef _DEBUG
		std::cout << "Visit node with code " << (int)node->letter << std::endl;
		std::cout << "Number of occurrences is " << static_cast<int>(node->value) << std::endl;
		std::cout << "Current path is ";
		typedef vector<char>::iterator Iter;
		for (Iter it = path.begin(); it != path.end(); ++it)
		{
			std::cout << *it;
		}
		std::cout << std::endl << std::endl;
#endif
		assert(nullptr != codingTable);
		codingTable->add(path, node->letter);
	}
}
